﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using System.Web;
using Rhapsody2Spotify.Lib;
using SpotiKat.Spotify.Entity;
using SpotiKat.Spotify.Manager;
using SpotiKat.Spotify.Core;

namespace Rhapsody2Spotify.Lib
{

    /// <summary>
    /// A class that can export Rhapsody tracks and playlists in a format easily imported into Spotify
    /// </summary>
    public class Rhapsody2SpotifyConverter
    {
        private readonly RhapsodyDB _rhapsodyDB;
        private readonly string _countryCode;

        /// <summary>
        /// The total number of tracks, including playlist tracks, that will be converted
        /// </summary>
        public int TrackCount { get { return _rhapsodyDB.GetPlaylistTrackCount() + _rhapsodyDB.GetLibraryTrackCount(); } }

        /// <summary>
        ///     Occurs after a track has been successfully proccessed
        /// </summary>
        public event EventHandler TrackProccessed;

        /// <summary>
        /// Called when track proccessed
        /// </summary>
        protected virtual void OnTrackProccessed()
        {
            if (TrackProccessed != null)
                TrackProccessed(this, EventArgs.Empty);
        }

        /// <summary>
        /// Creates a new Rhapsody2Spotify instance
        /// </summary>
        /// <param name="connectionString"></param>
        /// <param name="countryCode"></param>
        public Rhapsody2SpotifyConverter(string connectionString, string countryCode)
        {
            _rhapsodyDB = new RhapsodyDB(connectionString);
            _countryCode = countryCode;
        }

        /// <summary>
        /// Perform the conversion
        /// </summary>
        /// <param name="outputDirectory">Where to place the resultant html file</param>
        public void Execute(string outputDirectory)
        {
            var playlists = _rhapsodyDB.GetAllPlaylists();

            //Create a 'library' playlist of all the songs in the library (which is not a playlist)
            var plLibrary = new RPlaylist("Library", "Library", _rhapsodyDB.GetTracksFromLibrary());
            playlists.Add(plLibrary);

            ExportResults(playlists, outputDirectory);
        }

        /// <summary>
        /// Get the Spotify href for the track.
        /// </summary>
        /// <param name="rtrack"></param>
        private void GetSpotifyHref(RhapsodyTrack rtrack)
        {
            TrackSearchResult result = null;
            try
            {
                rtrack.SearchString = string.Format("artist:{0} track:{1}", rtrack.Artist, rtrack.TrackName);
                result = SearchManager.Instance.SearchTrack(rtrack.SearchString, 1);

                if (result.Success)
                {
                    foreach (Track t in result.Tracks)
                    {
                        if (t.Album.Availability.Contains(_countryCode) || t.Album.Availability.Contains("worldwide"))
                        {
                            rtrack.StatusDetail = t.Href;
                            rtrack.Status = TrackStatus.Available;
                            return;
                        }
                    }
                    rtrack.Status = TrackStatus.UnavailableGeographical;
                    rtrack.StatusDetail = string.Format("{0} tracks found, but none available in the specified territories", result.Tracks.Count);
                }
                else
                {
                    rtrack.Status = TrackStatus.UnavailableNoRecord;
                    rtrack.StatusDetail = string.Format("No tracks found for this record.");
                }
            }
            catch (SpotifyCommunicationException scex)
            {
                rtrack.Status = TrackStatus.UnavailableError;
                rtrack.StatusDetail = scex.Message;
            }
            catch (Exception ex)
            {
                rtrack.Status = TrackStatus.UnavailableError;
                rtrack.StatusDetail = ex.Message;

            }
        }

        /// <summary>
        /// Given the complete lists of playlists, generate the output file and save it to the outputDirectory
        /// </summary>
        /// <param name="playlists"></param>
        /// <param name="outputDirectory"></param>
        private void ExportResults(List<RPlaylist> playlists, string outputDirectory)
        {
            if (!Directory.Exists(outputDirectory))
                Directory.CreateDirectory(outputDirectory);
            Directory.SetCurrentDirectory(outputDirectory);


            using (FileStream fs = new FileStream(string.Format(@"{0}.html", "playlists"), FileMode.Create))
            {
                using (StreamWriter w = new StreamWriter(fs, Encoding.UTF8))
                {
                    ///Start of File
                    w.WriteLine(@"<!doctype html><html lang=en><head><meta charset=utf=8><title></title></head><body>");
                    w.WriteLine(@"<style>.playlist{margin:5px;padding:5px;border:solid 1px black;width:580px;margin-left:auto;margin-right:auto;padding-left:40px;}.trackwrapper{position:absolute;margin-left:-35px;margin-top:10px;width:32px;background-repeat:no-repeat;background-image: url();}");
                    w.WriteLine(@".tracks{width:32px;height:32px;opacity:0;overflow:hidden;}</style>");
                    w.WriteLine(@"<script type=""text/javascript"">function selectAll(id){if (document.selection){var div = document.body.createTextRange();div.moveToElementText(id);div.select();}else{var div = document.createRange();div.setStartBefore(id);div.setEndAfter(id) ;window.getSelection().addRange(div);}} </script>");


                    foreach (RPlaylist pl in playlists)
                    {
                        //Lookup all tracks in Spotify
                        foreach (RhapsodyTrack t in pl.Tracks)
                        {
                            GetSpotifyHref(t);
                            OnTrackProccessed();
                        }

                        ///start of playlist
                        w.WriteLine(string.Format(@"<div class=""playlist"">"));

                        ///good tracks
                        if (pl.Tracks.Where(t => t.Status == TrackStatus.Available).Count() > 0)
                        {
                            w.WriteLine(string.Format(@"<div class=""trackwrapper""><div id=""{0}"" onmouseover=""selectAll(this)"" class=""tracks"" >", pl.Name));
                            foreach (RhapsodyTrack t in pl.Tracks.Where(t => t.Status == TrackStatus.Available))
                            {
                                w.WriteLine(string.Format(@"<a href=""{0}"">{0}</a><br />", t.StatusDetail));
                            }
                            w.WriteLine(@"</div></div>");
                        }

                        ///summary
                        w.WriteLine(string.Format("<strong>{0}</strong><br />", pl.Name));
                        w.WriteLine(string.Format("Tracks Converted:{0}<br />", pl.Tracks.Where(t => t.Status == TrackStatus.Available).Count()));
                        w.WriteLine(string.Format("Tracks Unavailable:{0}<br />", pl.Tracks.Where(t => t.Status != TrackStatus.Available).Count()));


                        //////Bad Tracks
                        if (pl.Tracks.Where(t => t.Status != TrackStatus.Available).Count() > 0)
                        {
                            w.WriteLine(string.Format(@"<div class=""badtracks"">"));
                            foreach (RhapsodyTrack t in pl.Tracks.Where(t => t.Status != TrackStatus.Available))
                            {
                                w.WriteLine(string.Format(@"<a href=""http://ws.spotify.com/search/1/track?q={3}&page=1"">{0}-{1}</a>:<i>{2}</i><br />", t.Artist, t.TrackName, t.StatusDetail, HttpUtility.UrlEncode(t.SearchString)));
                            }
                            w.WriteLine(@"</div>");
                        }
                        w.WriteLine(@"</div>");

                    }

                    w.WriteLine(@"This product uses a SPOTIFY API but is not endorsed, certified or otherwise approved in any way by Spotify. Spotify is the registered trade mark of the Spotify Group.");
                    w.WriteLine(@"</body></html>");
                    ///end of file
                }

            }

        }
    }
}
